package com.ease.platform.dispatcher.support;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.ease.common.util.AopUtil;
import com.ease.common.util.Assertion;
import com.ease.common.util.Detect;
import com.ease.model.system.AuditLog;
import com.ease.platform.auditlog.support.AuditLogContext;
import com.ease.platform.dispatcher.vo.ImplementationDispatcherParam;

public class ImplementationDispatcherFactory<T> extends Detect {

	private Map<String, T> implementations;

	private T defaultImplementation;

	public T getImplementation(ImplementationDispatcherCallback implementationDispatcherCallback) {
		ImplementationDispatcherParam implementationDispatcherParam = new ImplementationDispatcherParam();
		implementationDispatcherCallback.buildImplementationDispatcherParam(implementationDispatcherParam);
		T implementation = this.getImplementation(implementationDispatcherParam);

		Assertion.notNull(implementation, "implementation not found, implementationDispatcherParam=" + implementationDispatcherParam);

		AuditLogContext auditLogContext = AuditLogContext.getAuditLogContext();
		if (null != auditLogContext) {
			AuditLog auditLog = auditLogContext.getAuditLog();
			if (null != auditLog) {
				if (null == auditLog.getTargetImplementation()) {
					Class<?> implementationClass = AopUtil.getTargetClass(implementation);
					if (null == implementationClass) {
						implementationClass = implementation.getClass();
					}
					auditLog.setTargetImplementation(implementationClass.getName());
				}
			}
		}

		return implementation;
	}

	private T getImplementation(ImplementationDispatcherParam implementationDispatcherParam) {
		if (null != implementationDispatcherParam) {
			T implementation = tryEntryKey(buildPossibleEntryKey(implementationDispatcherParam));
			if (null != implementation) {
				return implementation;
			}
		}
		return defaultImplementation;
	}

	private static List<String> buildPossibleEntryKey(ImplementationDispatcherParam implementationDispatcherParam) {
		ImplementationDispatcherParam tempImplementationDispatcherParam = implementationDispatcherParam;
		List<String> entryKeys = new ArrayList<String>();
		String entryKeyPrefix = "";
		String entryKey = null;

		while (null != tempImplementationDispatcherParam) {
			entryKey = tempImplementationDispatcherParam.getEntryKey();
			if (notEmpty(entryKey)) {
				if (notEmpty(entryKeyPrefix)) {
					// entryKeys.add(entryKeyPrefix +
					// BusinessServiceLocatorParam.DEFAULT_SERVICE_ENTRY_KEY_SUFFIX);
					entryKey = entryKeyPrefix + ImplementationDispatcherParam.ENTRY_KEY_SEPERATOR + entryKey;
				}
				entryKeys.add(entryKey);
				entryKeyPrefix = entryKey;
			}
			tempImplementationDispatcherParam = tempImplementationDispatcherParam.getNext();

		}
		return entryKeys;
	}

	private T tryEntryKey(List<String> entryKeys) {
		if (notEmpty(entryKeys) && null != implementations) {
			for (int i = entryKeys.size() - 1; i >= 0; i--) {
				String entryKey = entryKeys.get(i);
				if (implementations.containsKey(entryKey)) {
					return implementations.get(entryKey);
				}
			}
		}
		return null;
	}

	/**
	 * @return the implementations
	 */
	// public Map<String, T> getImplementations() {
	// return implementations;
	// }
	/**
	 * @param implementations
	 *            the implementations to set
	 */
	public void setImplementations(Map<String, T> implementations) {
		this.implementations = implementations;
	}

	/**
	 * @return the defaultImplementation
	 */
	// public T getDefaultImplementation() {
	// return defaultImplementation;
	// }
	/**
	 * @param defaultImplementation
	 *            the defaultImplementation to set
	 */
	public void setDefaultImplementation(T defaultImplementation) {
		this.defaultImplementation = defaultImplementation;
	}

	// public static void main(String[] args) {
	// ImplementationDispatcherParam implementationDispatcherParam = new
	// ImplementationDispatcherParam();
	// implementationDispatcherParam.add("A");
	// implementationDispatcherParam.add("B");
	// implementationDispatcherParam.add("C");
	// implementationDispatcherParam.add("D");
	// ImplementationDispatcher.buildPossibleEntryKey(implementationDispatcherParam);
	//
	// }

}
